package com.zisu.a996.stream;

import com.alibaba.fastjson.JSON;
import com.zisu.a996.lambda.cart.CartService;
import com.zisu.a996.lambda.cart.Sku;
import com.zisu.a996.lambda.cart.SkuCategory;
import org.junit.Before;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import javax.swing.plaf.synth.SynthOptionPaneUI;
import java.util.*;

/**
 * @Author: 蔡翔
 * @Date: 2019/11/23 20:32
 * @Version 1.0
 * 演示流的各种操作
 */

public class StreamOperation {



    /**
     *    中间操作 演示
     **/

    List<Sku> list = CartService.getCartSkuList();
    @Before
    public void init(){
        list = CartService.getCartSkuList();
    }

    @Test
    public void filterTest(){
        list.stream()
                // 等于书籍类的要保留，不等于书籍类的 过滤掉
                // filter 返回为true 就是保留的，返回为false 就是不保留的。
                .filter(
                        sku -> SkuCategory.BOOK.equals(sku.getSkuCategory())
                )
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
        ;
    }

    /**
     * 将一个元素 转化成另外一个元素。
     **/
    @Test
    public void mapTest(){
        list.stream()
                //map()接受的是Function<T,R>  ,这里是吧
                .map(sku -> sku.getSkuName())

                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }


    @Test
    public void flatMapTest(){
        list.stream()
                //map()接受的是Function<T,R>  ,这里是吧
                .flatMap(sku ->
                        //返回的是一个 “合成流”，这个合成流 是由每一个 小流 合成的，这里的小流 是 每个SkuName.split 的
                    Arrays.stream(sku.getSkuName().split(""))
                )
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }

    /**
     * peek 无状态的 中间操作，因为是中间操作并不会对流进行销毁，而是执行完后 传递给下一步操作。forEach()是终端操作会销毁。
     **/
    @Test
    public void peekTest(){
        list.stream()
                //peek 和 foreach 一样，只不过peek 是个中间操作，函数式接口返回值为void (不能写，只能调用某些其他的方法。)
                // 结果：并不是 peek() 全执行完 在执行forEach() 而是 一个流数据，先执行完 peek再执行foreach，再第二个流数据，接着这么流
                // peek是无状态的操作，它和foreach谁先执行，对最后的结果都无影响。所以就混合了。
                .peek(i->System.out.println(i.getSkuName()))
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }


    /**
     * sort 有状态的 中间操作
     **/
    @Test
    public void sortTest(){
        list.stream()
                .peek(i->System.out.println(i.getSkuName()))
                //SORT是有状态操作，这样 上面的peek 就不会和foreach 混合输出了，因为sort有状态值，影响后面的最终数据。
                .sorted(Comparator.comparing(Sku::getTotalPrice))
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }

    /**
     * 去重操作
     **/
    @Test
    public void distinctTest(){
        list.stream()
                .map(sku -> sku.getSkuCategory())
                .distinct()
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }

    /**
     * skip 跳过前几条 数据
     **/
    @Test
    public void skipTest(){
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice))
                //跳过前三条数据
                .skip(3)
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }

    /**
     * limit 只取前三条
     **/
    @Test
    public void limitTest(){
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice))
                //跳过前三条数据
                .limit(3)
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });
    }

    /**
     * limit 和 skip 组合使用 实现假分页功能
     **/
    @Test
    public void fakePageTest(){
        Integer num = 1;
        Integer size = 2;
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice))
                .skip(num*size)
                .limit(size)
                .forEach(i->{
                    System.out.println(
                            JSON.toJSONString(i,true)
                    );
                });

    }


    /**
     *    终端操作演示（短路）
     **/

    //allMatch使用:终端操作，短路操作..只要全部满足才返回true
    @Test
    public void allMatchTest(){
        boolean b = list.stream()
                .peek(sku -> System.out.println(sku.getTotalPrice()))
                .allMatch(sku -> sku.getTotalPrice() > 100);
    }

    //anyMatch 是只要有一个满足就会返回true
    @Test
    public void anyMatchTest(){
        //注意 anyMatch 只要匹配到一个满足情况 就会停止操作。
        boolean b = list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .anyMatch(sku -> sku.getTotalPrice() > 100);
        System.out.println(b);
    }

    //所有都没匹配上 返回true
    @Test
    public void noneMatchTest(){
        //注意 anyMatch 只要匹配到一个满足情况 就会停止操作。
        boolean b = list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .noneMatch(sku -> sku.getTotalPrice() > 100000);
        System.out.println(b);
    }

    //找到第一个
    @Test
    public void findFirstTest(){
        //Optional 有一个好处它是可以判断为空的。
        Optional<Sku> first = list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .findFirst();
        System.out.println(JSON.toJSONString(first.get()));
    }

    //findAny 也是随意的找一个，它在并行上 比findFirst要快（但是有一个缺点 就是会随机匹配到一个元素）。
    @Test
    public void findAnyTest(){
        //Optional 有一个好处它是可以判断为空的。
        Optional<Sku> any = list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .findAny();
        System.out.println(JSON.toJSONString(any.get(),true));
    }


    /**
     *    终端操作演示（非短路）
     **/

    //max 的使用
    @Test
    public void maxTest(){
        OptionalDouble max = list.stream()
                .mapToDouble(Sku::getTotalPrice)
                //.map(Sku::getTotalPrice)
                //注意max() 必须要根据你实际的要排序的类型来，不能用map() 要 mapToDouble() 类似的，
                .max();
        System.out.println(max.getAsDouble());
    }
    @Test
    public void minTest(){
        OptionalDouble min = list.stream()
                .mapToDouble(Sku::getTotalPrice)
                //.map(Sku::getTotalPrice)
                //注意max() 必须要根据你实际的要排序的类型来，不能用map() 要 mapToDouble() 类似的，
                .min();
        System.out.println(min.getAsDouble());
    }

    @Test
    public void countTest(){
        long count = list.stream()
                .count();
        System.out.println(count);
    }

}
